#!/bin/ksh
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
# ident	"%Z%%M%	%I%	%E% SMI"
#
#	printer interface script for printers with a URI instead of
#	device name.
#
# The existence of a "PPD" environment variable in the calling environment
# indicates that Foomatic is to be used for filtering all job data as it is
# streamed to the output device (printer).
#
# The contents of a "DEVICE_URI" environment variable in the calling
# environment indicates the method and endpoint used in communicating with
# the output device (printer).  If no DEVICE_URI is present or the value
# contains a missing or unknown scheme, the URI scheme is assumed to be
# "file" and output streaming will be handled accordingly.

export PATH=/bin:/usr/bin:/usr/lib/lp/bin:/usr/sfw/bin

TAG="uri-interface"


# Re-arrange fds for later use
exec 5>&2 2>/dev/null 3>&1

#
# Exit Codes:
#
EXIT_OK=0
EXIT_FATAL=1
EXIT_TERM=128
EXIT_RETRY=129

fail() {	# exit-code "message"
	logger -p lpr.error -t ${TAG} "${2}"
	echo ${2} >&5
	exit ${1}
}

# signal handling
#   EXIT   0  - normal exit
#   HUP    1  - the output stream disconnected
#   INT    2  - the output stream interupted us
#   QUIT   3  - the output stream interupted us
#   TERM  15  - we have been cancelled or shutdown

catch_exit() {
	exit $exit_code
}

catch_disconnect() {
	fail ${EXIT_RETRY} "connection to the printer dropped; off-line?"
}
	
catch_interrupt() {
	fail ${EXIT_RETRY} "interrupt from the printer; baud-rate issues?"
}

catch_cancellation() {
	fail ${EXIT_RETRY} "job cancelled"
}

trap 'catch_disconnect()' HUP
trap 'catch_interrupt()' INT QUIT
trap 'catch_cancellation()' TERM

parse_uri() {	# scheme://[[user[:password]@]host[:port]]/path
	URI_SCHEME=$(expr "$1" : "\(.*\)://.*")
}

parse() {
	echo "$(expr \"$1\" : \"^[^=]*=\(.*\)\")"
}

#
#	Generate an ASCII burst page and pass it to the printer
# This may be much faster than the PostScript(TM) burst page
#
ascii_burst_page() {
	cat <<EOF
	${title}
	Request: ${request_id}
	User: ${user}
	Printer: ${printer}
	Time: $(date)
	Copies: ${copies}
EOF
	tput ff
}

#
#	Generate a PostScript(TM) burst page (this assumes an 8.5x11 page size)
#
postscript_burst_page() {
	cat <<-EOF
	%!ps
	/PrintLine { exch findfont exch scalefont setfont moveto show } def
	newpath 4 setlinewidth 1 setlinejoin
	15 760 moveto 595 760 lineto 595 585 lineto 15 585 lineto closepath
	gsave .75 setgray fill grestore
	0 setgray stroke
	(${user}) 30 730 /Times-Bold 24 PrintLine
	(${request_id}) 415 730 /Times-Bold 24 PrintLine
	(${printer}) 30 600 /Times-Bold 16 PrintLine
	($(date)) 350 600 /Times-Roman 16 PrintLine
	(${title}) 100 660 /Times-Bold 36 PrintLine
	(Copies: ${copies}) 30 25 /Times-Roman 16 PrintLine
	showpage
	EOF
}

logger -p lpr.debug -t ${TAG} "$0 $*"

#
# Detemine if we were called correctly
#
if [[ $# -lt 5 ]] ; then
	fail ${EXIT_FATAL} "wrong number of arguments to interface script"
fi


printer=$(basename $0)
request_id=$1
user=$2
title=$3
copies=$4
options=$5

shift 5
files="$*"

burst_page="postscript_burst_page"

for i in ${options}
do
	case "${i}" in

	nobanner )
		burst_page=""
		;;

	nofilebreak )
		nofilebreak="yes"
		;;

	burst-page-type=* )
		burst_page="$(parse ${i})_burst_page"
		;;

	* )
		logger -p lpr.error -t ${TAG} \
			"unrecognized \"-o ${i}\" option, ignored" 1>&2
		;;
	esac
done


#
# Procss the DEVICE_URI if we have one
#
if [[ -n "${DEVICE_URI}" ]] ; then
	parse_uri ${DEVICE_URI}		# split up the URI

	URI_SCHEME=${URI_SCHEME:-file}	# if there is no scheme, assume "file"

	case "${URI_SCHEME}" in
	file|usb|ecpp|serial|parallel)
		IO_HANDLER="lp.cat"
		IO_HANDLER_ARGS=""
		;;
	smb)
		IO_HANDLER="smbspool"
		IO_HANDLER_ARGS="${request_id} ${user} \"${title}\" 1
				 \"${options}\""
		;;
	tcp|socket)
		URI_HOST=$(expr "${DEVICE_URI}" : ".*://\([^:/]*\)")
		URI_PORT=$(expr "${DEVICE_URI}" : ".*://.*:\([^/]*\)")
		if [[ -z "${URI_HOST}" ]] ; then
			fail ${EXIT_FATAL} "invalid device-uri: ${DEVICE_URI}, reset with lpadmin -v"
		fi
		URI_PORT=${URI_PORT:-"9100"}
		IO_HANDLER="telnet"
		IO_HANDLER_ARGS="-c -E ${URI_HOST} ${URI_PORT}"
		;;
	lpd|ipp)
		IO_HANDLER="lp"
		IO_HANDLER_ARGS="-s -d ${DEVICE_URI}"
		;;
	*)
		IO_HANDLER=${URI_SCHEME}
		IO_HANDLER_ARGS=""
		;;
	esac
fi
IO_HANDLER=${IO_HANDLER:-"lp.cat"} # if IO_HANDLER is still unset, use lp.cat

# determine if the IO handler is available for us to use when communicating with
# the output device (printer.)
whence ${IO_HANDLER} >/dev/null
if [[ $? -ne 0 ]] ; then
	fail ${ERR_FATAL} \
		"Interface script unable to locate IO handler: ${IO_HANDLER}"
fi

#  There is a PPD file specified, so use foomatic
if [[ -n "${PPD}" ]] ; then
	FILTER_CHAIN="| foomatic-rip"
fi

#
# Start processing the job here
#
set | logger -p lpr.debug -t "${TAG}"

(
	if [[ -n "${burst_page}" ]] ; then
		eval "${burst_page} ${FILTER_CHAIN}"
	fi
	while [[ $copies -gt 0 ]] ; do
		for file in ${files} ; do
			if [[ -r "${file}" ]] ; then
				eval "cat ${file} ${FILTER_CHAIN}"
			fi
		done
		copies=$(( copies - 1 ))
	done
) | ${IO_HANDLER} ${IO_HANDLER_ARGS}

exit ${EXIT_OK}
